#pragma once

#include "Sem.hpp"
#include <vector>
#include "Mutex.hpp"

using namespace SemMoudle;
using namespace MutexModule;

template <typename T>
class RingQueue
{
public:
    RingQueue()
        : _cap(5),
          _blank_sem(_cap),
          _p_step(0),
          _c_step(0),
          _data_sem(_cap)
    {
        _q.resize(_cap);
    };

    void Equeue(const T &in)
    {
        // 先把信号量瓜分再申请锁
        // 申请空位置信号量
        _blank_sem.P();

        LockGuard mutexguard(_pmutex);

        _q[_p_step] = in;
        _p_step = (_p_step + 1) % _cap;

        // 通知数据信号量
        _data_sem.V();
    }

    void Pop(T *out)
    {
        // 申请数据信号量
        _data_sem.P();

        LockGuard mutexguard(_cmutex);

        *out = _q[_c_step];
        _c_step = (_c_step + 1) % _cap;

        // 通知空位置信号量
        _blank_sem.V();
    }

    ~RingQueue() {};

private:
    std::vector<T> _q;
    int _cap;

    Sem _blank_sem;
    int _p_step;

    Sem _data_sem;
    int _c_step;

    Mutex _pmutex;
    Mutex _cmutex;
};